package com.example.examwlxy.playwright;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.example.examwlxy.ExamWlxyApplication;
import com.example.examwlxy.entity.AccountEntity;
import com.microsoft.playwright.*;
import com.microsoft.playwright.options.LoadState;
import com.microsoft.playwright.options.WaitForSelectorState;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class PlaywrightExample {

    // 使用静态变量管理Playwright和Browser实例
    private static Playwright playwright;
    private static Browser browser;
    //    登录用户界面信息
    public static ConcurrentHashMap<String, Page> pageMaps = new ConcurrentHashMap<>();
    /**
     * 账号信息
     */
    public static List<AccountEntity> accountList = new ArrayList<>();
    //  科目信息
    public static TreeSet<String> examNameSet = new TreeSet<>();

    public static String excelUrl= System.getProperty("user.dir");

    static String scriptContent = null;

    static {
        try {
            scriptContent = new String(Files.readAllBytes(Paths.get(excelUrl+"/lib/wl.js")));
            readAccountInfo();
            // 初始化Playwright和Browser
            playwright = Playwright.create();
//            browser =  playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));  // 显示浏览器窗口.setSlowMo(50));
            browser =  playwright.chromium().launch();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {

//        try {
//            login("lijd615", "Wdnmdzz00.");
//            System.out.println(examNameSet);
//            startExam("lijd615","","");
//            System.out.println("按任意键退出...");
//            System.in.read();
//            playwright.close();
//            browser.close();
//            closePage();
//        } catch (Exception e) {
//            e.printStackTrace();
//        } finally {
//            // 关闭资源
//            pageMaps.values().forEach(Page::close);
//            if (browser != null) browser.close();
//            if (playwright != null) playwright.close();
//        }
    }

    private static void closePage() {
        for (Page value : pageMaps.values()) {
            value.close();
        }
    }

    public static boolean login(String account, String password) {
        try {
            Page page = pageMaps.get(account);
            if (page == null) {
                page = createPageAccount(account);
            } else {
                return true;
            }
            page.navigate("https://sia.sinopec.com/page/#/college/index");
            page.waitForSelector(".login-btn").click();

            // 输入账号
            page.waitForSelector("input[placeholder='请输入统一账号']").fill(account);

            // 输入密码（增强版）
            page.waitForSelector("input[placeholder='请输入密码']",
                    new Page.WaitForSelectorOptions().setState(WaitForSelectorState.VISIBLE));
            page.waitForSelector("input[placeholder='请输入密码']").click();
            page.locator("input[placeholder='请输入密码']").clear();
            page.waitForSelector("input[placeholder='请输入密码']").fill(password);

            // 点击登录按钮
            page.waitForSelector("button:has-text('立即登录')").click();
            //等待元素
            page.waitForSelector(".quantity .list .item");
            page.locator(".quantity .list .item").nth(4).click();

            page.waitForSelector(".studyContent .content .table ul li");
            //获取 科目
            List<Locator> allClass = page.locator(".studyContent .content .table ul li").all();
            for (Locator classData : allClass) {
                String examName = classData.locator("h4").textContent();
                String startTime = timeFilter(classData.locator("p").nth(0).textContent());
                String endTime = timeFilter(classData.locator("p").nth(1).textContent());
                System.out.println("考试名称：" + examName);
                examNameSet.add(examName);
            }
            clickDocument(page) ;
        } catch (Exception e) {
            System.out.println("出错了跳过 开始下一个"+"---错误账号："+account);

            if (pageMaps.get(account)!=null&&!pageMaps.get(account).isClosed()) {
                pageMaps.get(account).close();
            }
            pageMaps.remove(account) ;
            return false;
        }
        return true;

    }

    public static void clickDocument(Page page){
        // 定义目标元素的CSS选择器
        String selector = "#app > div > div.network-college-body > section > div > div.centerDialog > div:nth-child(2) > div > div > div.el-dialog__header > button";

        // 检测元素是否存在
        if (page.isVisible(selector)) {

            // 点击元素（添加重试机制和超时设置）
            page.click(selector, new Page.ClickOptions()
                    .setTimeout(5000) // 设置超时时间为5秒
                    .setForce(true)); // 强制点击，即使元素被遮挡
        } else {
            System.out.println("不存在意外窗口，跳过点击操作");
        }

    }

    public static void startExam(String account, String examName, String score) throws InterruptedException, TimeoutException {
        Page page = pageMaps.get(account);
        //获取 科目
        List<Locator> allClass = page.locator(".studyContent .content .table ul li").all();
        for (Locator classData : allClass) {
            Locator h4 = classData.locator("h4");
            String title = h4.textContent();
            if (examName.equals(title)) {
                Locator enterButton = classData.locator(".btn:has-text('进入')"); // 定位“进入”按钮
                enterButton.click();
                //弹窗确认
                alertWindow(page);

                // 定义期望分数
                int targetScore = Integer.parseInt(score);
                scriptContent = modifyScriptForTargetScore(scriptContent, targetScore);
                Page currentActivePage = getCurrentActivePage(account);
                System.out.println(currentActivePage.url());
                currentActivePage.waitForLoadState(LoadState.NETWORKIDLE);
                Object evaluate = currentActivePage.evaluate(scriptContent);
                System.out.println("账号："+account+"-------"+evaluate);
                currentActivePage.locator(".el-main .user-exam-submit:has-text('我要交卷')").click();
                currentActivePage.waitForSelector(".el-dialog__footer button");
                currentActivePage.locator(".el-dialog__footer button").all().get(1).click();
                alertWindow(currentActivePage);
                currentActivePage.close();
                break;
            }

        }
    }


    /**
     * 等待 BrowserContext 中的 pages 数量达到指定值
     *
     * @param expectedCount 期望的页面数量
     * @param timeoutMs     超时时间（毫秒）
     * @throws InterruptedException 如果等待被中断
     * @throws TimeoutException     如果超时仍未达到期望数量
     */
    public static List<Page> waitForPageCount(Page mainPage, int expectedCount, long timeoutMs)
            throws InterruptedException, TimeoutException {
        long startTime = System.currentTimeMillis();

        while (System.currentTimeMillis() - startTime < timeoutMs) {
            BrowserContext context = mainPage.context();
            List<Page> pages = context.pages();
            if (pages.size() >= expectedCount) {
                return pages; // 达到期望数量，退出等待
            }
            System.out.println(pages);
            Thread.sleep(500); // 短暂等待后重试
        }

        // 超时处理
        throw new TimeoutException(String.format(
                "等待页面数量达到 %d 超时（%d ms），当前数量: %d",
                expectedCount, timeoutMs, mainPage.context().pages().size()
        ));
    }


    /**
     * 获取指定账号对应的浏览器上下文中的当前活动页面
     *
     * @param account 账号
     * @return 当前活动页面，如果未找到则返回null
     */
    public static Page getCurrentActivePage(String account) throws InterruptedException, TimeoutException {
        Page mainPage = pageMaps.get(account);
        if (mainPage == null) {
            System.err.println("未找到账号对应的主页面: " + account);
            return null;
        }

        BrowserContext context = mainPage.context();
        List<Page> pages = waitForPageCount(mainPage, 2, 30000);
        if (pages.isEmpty()) {
            System.err.println("上下文中没有打开的页面");
            return null;
        }

        // 返回最后一个打开的页面（通常是当前活动页面）
        return pages.get(pages.size() - 1);
    }

    public static void sleepAuto(int m) {
        try {
            Thread.sleep(1000L * m);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 替换分数
     *
     * @param script
     * @param targetScore
     * @return
     */
    private static String modifyScriptForTargetScore(String script, int targetScore) {
        // 移除原有的分数区间设置
        script = script.replace("const targetScore = 80;", "const targetScore = " + targetScore + ";");
        return script;
    }

    /**
     * 点击弹窗确认
     *
     * @param page
     */
    public static void alertWindow(Page page) {
        // 定义确认按钮的Locator，使用更精确的选择器
        Locator confirmButton = page.locator(".conteneDlg .btn button:has-text('确认')");

        try {
            // 等待确认按钮出现并可点击（默认超时30秒）
            confirmButton.waitFor(new Locator.WaitForOptions().setTimeout(4000)
                    .setState(WaitForSelectorState.VISIBLE));

            // 点击确认按钮前添加日志
            System.out.println("确认按钮已找到，准备点击");

            // 使用force选项确保点击（处理覆盖层等特殊情况）
            confirmButton.click(new Locator.ClickOptions().setForce(true));

            System.out.println("成功点击确认按钮");
        } catch (TimeoutError e) {
            // 超时处理：确认按钮未在指定时间内出现
            System.out.println("确认按钮未在4秒内出现或不可点击");
        }

    }

    /**
     * 时间过滤
     *
     * @param textTime 需要过滤的包含时间的字符串
     * @return
     */
    public static String timeFilter(String textTime) {
        // 正则表达式匹配时间格式
        Pattern pattern = Pattern.compile(":\\s*(\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2})");
        Matcher matcher = pattern.matcher(textTime);
        if (matcher.find()) {
            System.out.println(matcher.group(1));
            return matcher.group(1);
        }
        return null;
    }

    /**
     * 创建一个page
     *
     * @param account 账号
     * @return
     */
    public static Page createPageAccount(String account) {
        try {
            // 使用已初始化的browser创建上下文和页面
            BrowserContext context = browser.newContext(new Browser.NewContextOptions()
                    .setJavaScriptEnabled(true)); // 启用JavaScript支持
            Page page = context.newPage();
            pageMaps.put(account, page);
            return page;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void readAccountInfo() {
        accountList = new ArrayList<>();
        EasyExcel.read(excelUrl+"/lib/accountAndPassword.xls")
                .head(AccountEntity.class)
                .sheet()
                .registerReadListener(new AnalysisEventListener<AccountEntity>() {
                    @Override
                    public void invoke(AccountEntity data, AnalysisContext context) {
                        accountList.add(data);
                    }

                    @Override
                    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

                    }
                })
                .doRead();
        System.out.println(accountList);
    }

}